module VgaController( 
  // Host Side
  iData,
  oAddress,      //Actual Pixel's memory address
  oReadEn,       //Actual Pixel's validity
  oVgaX,
  oVgaY,
  // VGA Side
  oVgaRgb,
  oVgaHs,
  oVgaVs,
  // Control Signal
  iClk,
  iRstN,
  iEn
);

// Host Side
output reg [9:0] oVgaX = 0;
output reg [9:0] oVgaY = 0;
output reg [18:0] oAddress = 0;
output reg oReadEn = 0;
input [3:0] iData;
// VGA Side
output [3:0] oVgaRgb;
output reg oVgaHs = 0;
output reg oVgaVs = 1;
// Control Signal
input iClk;
input iRstN;
input iEn;

// ------------------- Parameters--------------------------------------------
// Horizontal Parameter ( Pixel )
parameter H_SYNC_CYC   = 96;
parameter H_SYNC_BACK  = 48;
parameter H_SYNC_ACT   = 640;
parameter H_SYNC_FRONT = 16;
parameter H_SYNC_TOTAL = 800;
// Virtical Parameter  ( Line )
parameter V_SYNC_CYC   = 2;
parameter V_SYNC_BACK  = 33;
parameter V_SYNC_ACT   = 480;
parameter V_SYNC_FRONT = 10;
parameter V_SYNC_TOTAL = 525;
// Start Offset
parameter X_START = H_SYNC_CYC+H_SYNC_BACK+4;
parameter Y_START = V_SYNC_CYC+V_SYNC_BACK;
parameter H_BLANK = H_SYNC_FRONT+H_SYNC_CYC+H_SYNC_BACK;
parameter V_BLANK = V_SYNC_FRONT+V_SYNC_CYC+V_SYNC_BACK;

// -------------------- Internal Registers and Wires -------------------------
reg [9:0] hCount = 0;
reg [9:0] vCount = 0;
reg [3:0] rgb = 0;

// -------------------- assigns ----------------------------------------------
assign oVgaRgb = (hCount >= X_START && hCount < X_START + H_SYNC_ACT &&
                  vCount >= Y_START && vCount < Y_START + V_SYNC_ACT)
                  ? rgb : 4'd0;

// --------------------- always blocks ---------------------------------------
always@(posedge iClk or negedge iRstN)begin
  if(!iRstN) begin
    rgb <= 4'b0;
  end
  else begin
    if(oReadEn && iClk && iEn) begin
      rgb <= iData;
    end
    else begin
      rgb <= 3'd0;
    end
  end
end

// Pixel LUT Address Generator
always@(posedge iClk or negedge iRstN)
begin
  if(!iRstN) begin
    oVgaX <= 10'd0;
    oVgaY <= 10'd0;
    oAddress <= 19'd0;
    oReadEn <= 1'b0;
  end
  else begin
    if( hCount >= X_START && hCount < X_START + H_SYNC_ACT &&
        vCount >= Y_START && vCount < Y_START + V_SYNC_ACT )
    begin
      oVgaX <= hCount - X_START;
      oVgaY <= vCount - Y_START;
      oAddress <= oVgaY * H_SYNC_ACT + oVgaX;
      oReadEn  <= 1'b1;
    end
    else begin
      oReadEn <= 1'b0;
    end
  end
end
 
// H_Sync Generator, Ref. 25.175 MHz Clock
always@(posedge iClk or negedge iRstN)
begin
  if(!iRstN) begin
    hCount <= 10'd0;
    oVgaHs <= 1'b0;
  end
  else begin
    // H_Sync Counter
    if( hCount < H_SYNC_TOTAL ) hCount <= hCount+1'b1;
    else hCount <= 10'd0;
    // H_Sync Generator
    if( hCount < H_SYNC_CYC )oVgaHs <= 1'b0;
    else oVgaHs <= 1'b1; 
  end
end

 
// V_Sync Generator, Ref. H_Sync
always@(posedge iClk or negedge iRstN)
begin
  if(!iRstN) begin
    vCount <= 10'd0;
    oVgaVs <= 1'b0;
  end
  else begin
    // When H_Sync Re-start
    if(hCount==10'd0) begin
      // V_Sync Counter
      if( vCount < V_SYNC_TOTAL ) vCount <= vCount + 1'b1;
      else vCount <= 10'd0;
      // V_Sync Generator
      if( vCount < V_SYNC_CYC ) oVgaVs <= 1'b0;
      else oVgaVs <= 1'b1;
    end
  end
end

endmodule
